package com.dalin.framework.common.utils;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.Random;

import com.dalin.framework.common.utils.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.dalin.framework.common.PropertyConst;


/*****************************************************************************
 * @content: 常用关于数值型数据方法汇总                                                                                                                             *
 * @author : 那建林                                                                                                                                                                   *
 * @crtDate: 2010-02-03                                                     *
 ****************************************************************************/
public final class NumberUtils {
	private NumberUtils() {} // 不允许构造
	private static final Log log = LogFactory.getLog(NumberUtils.class);
	
	
	/*************************************************************************
	 * @content: 检查给定参数是否为整型数值，包括正整数，0,负整数
	 * @param  : str 待检验字符串
	 * @return : boolean
	 * @author : 那建林
	 * @crtDate: 2010-03-15
	 * @modDate: 2010-03-15
	 */
	public static boolean isIntegerType(String str) {
		if (StringUtils.isBlank(str)) return false;
		return str.matches("-?\\d+");
	}
	
	
	/*************************************************************************
	 * @content: 检查给定参数是否为小数
	 * @param  : str 待检验字符串
	 * @return : boolean
	 * @author : 那建林
	 * @crtDate: 2010-03-15
	 * @modDate: 2010-03-15
	 */
	public static boolean isDecimalType(String str) {
		if (StringUtils.isBlank(str)) return false;
		return str.matches("-?\\d+\\.\\d+");
	}
	
	
	/*************************************************************************
	 * @content: 检查给定参数是否为正数
	 * @param  : str 待检验字符串
	 * @return : boolean
	 * @author : 那建林
	 * @crtDate: 2010-03-15
	 * @modDate: 2010-03-15
	 */
	public static boolean isPositive(String str) {
		if (StringUtils.isBlank(str)) return false;
		return str.matches("\\d+\\.?\\d+");
	}
	
	
	/*************************************************************************
	 * @content: 检查给定参数是否为正整数
	 * @param  : str 待检验字符串
	 * @return : boolean
	 * @author : 那建林
	 * @crtDate: 2010-03-15
	 * @modDate: 2010-03-15
	 */
	public static boolean isPositiveInteger(String str) {
		if (StringUtils.isBlank(str)) return false;
		return str.matches("\\d+");
	}
	
	
	/*************************************************************************
	 * @content: 检查给定参数是否为正小数
	 * @param  : str 待检验字符串
	 * @return : boolean
	 * @author : 那建林
	 * @crtDate: 2010-03-15
	 * @modDate: 2010-03-15
	 */
	public static boolean isPositiveDecimal(String str) {
		if (StringUtils.isBlank(str)) return false;
		return str.matches("\\d+\\.\\d+");
	}
	
	
	/*************************************************************************
	 * @content: 检查给定参数是否为素数
	 * @param  : x 待检验数字
	 * @return : boolean 是质数返回true
	 * @author : 那建林
	 * @crtDate: 2010-03-17
	 * @modDate: 2010-03-17
	 */
	public static boolean isPrimeNumber(int x) {
		if (x < 2) return false;
		int len = x / 2 + 1;
		for (int i = 2; i < len; i++) {
			if (x % i == 0) return false;
		}
		return true;
	}
	
	
	/*************************************************************************
	 * @content: 转换成两位小数
	 * @param  : d 待转换的double数值
	 * @return : String
	 * @author : 那建林
	 * @crtDate: 2010-04-23
	 * @modDate: 2010-04-23
	 */
	public static String formatTwoDigitDouble(Double d) {
		DecimalFormat df = new DecimalFormat("0.##");   
		return df.format(d);
	}
	
	
	/*************************************************************************
	 * @content: 给定字符串最后的有效数字部分加1，如：001-->002，Abc009-->Abc010
	 *           如果遇到极端情况，数字部分满位，即Abc999,则返回字串长度加一位，变成Abc1000
	 * @param  : thisNumber 末位有效数字加1后的字符串，如果最后部分不为数字，返回null
	 * @return : String 
	 * @author : 那建林
	 * @crtDate: 2010-03-15
	 * @modDate: 2010-03-15
	 */	
	public static String getNextStrNum(String thisNumber) {
		if (StringUtils.isBlank(thisNumber) 
				|| !thisNumber.matches(".*\\d+")) {
			log.error(thisNumber + "has not a number type at last.");
			return null;
		}
		String[] numStrArray = thisNumber.split("\\D+");
		String numStr = numStrArray[numStrArray.length - 1];
		long num = Long.parseLong(numStr);
		return thisNumber.substring(0, thisNumber.length()
				- String.valueOf(num + 1).length()) + (num + 1);
	}
	
	
	/*************************************************************************
	 * @content: 按指定区间产生随机整数
	 * @param  : arrayLength 产生几位随机整数
	 * @param  : minValue 随机数的最小值
	 * @param  : maxValue 随机数的最大值
	 * @return : 包括 arrayLength 位随机数的数组
	 * @author : 那建林
	 * @crtDate: 2010-02-03
	 * @modDate: 2010-02-14
	 */
	public static int[] getRandomIntArray(
			int arrayLength, int minValue, int maxValue) {
		if (arrayLength <= 0) {
			log.warn("数组长度必须为正数.");
			return null;
		}
		if (maxValue < minValue) {
			log.warn("请注意随机数产生区间，最大值必须不能小于最小值.");
			return null;
		}
		Random rand = new Random();
		int[] arrayInt = new int[arrayLength];
		for (int i = 0; i < arrayLength; i++) {
			arrayInt[i] = rand.nextInt(maxValue - minValue + 1) + minValue;
		}
		return arrayInt;
	}
	
	
	/*************************************************************************
	 * @content: 按指定区间产生一个随机整数
	 * @param  : minValue 随机数的最小值
	 * @param  : maxValue 随机数的最大值
	 * @return : int 整数
	 * @author : 那建林
	 * @crtDate: 2010-03-02
	 * @modDate: 2010-03-02
	 */
	public static int getRandomInt(int minValue, int maxValue) {
		if (maxValue < minValue) {
			log.warn("请注意随机数产生区间，最大值必须不能小于最小值.");
			return 0;
		}
		Random rand = new Random();
		return rand.nextInt(maxValue - minValue + 1) + minValue;
	}

	
	/*************************************************************************
	 * @content: 查找数组中和最大的连续区间值,第一种方法最快，100W个数不到15ms左右
	 * @param  : arrayInt 随机数组
	 * @return : maxSum
	 * @author : 那建林
	 * @crtDate: 2010-02-14
	 * @modDate: 2010-02-14
	 */
	public static int getMaxSucArraySum1(int[] arrayInt) {
		int maxSum = 0;
		int tempSum = 0;
		for (int i : arrayInt) {
			tempSum = Math.max(tempSum + i, 0);
			maxSum = Math.max(maxSum, tempSum);
		}
		log.info("数组最大连续和:" + maxSum);
		return maxSum;
	}
	public static int getMaxSucArraySum2(int[] arrayInt) {
		int maxSum = arrayInt[0];
		int tempInt = 0;
		int beginPos = 0;
		int endPos = 0;
		for (int i = 0; i < arrayInt.length; i++) {
			for (int j = i; j < arrayInt.length; j++) {
				tempInt += arrayInt[j];
				if (tempInt > maxSum) {
					maxSum = tempInt;
					beginPos  = i;
					endPos = j;
				}
			}
			tempInt = 0;
		}
		log.info("数组最大连续和:" + maxSum + ", 位置：" 
				+ beginPos + "-" +endPos);
		return maxSum;
	}
	
	
	/*************************************************************************
	 * @content: 交换数组元素
	 * @param  : x[] 待交换元素的数组
	 * @param  : a 数组索引a
	 * @param  : b 数组索引b
	 * @author : 那建林
	 * @crtDate: 2010-02-16
	 * @modDate: 2010-02-16
	 */
	public static void swap(int x[], int a, int b) {
		int t = x[a];
		x[a] = x[b];
		x[b] = t;
	}
	public static void swap(long x[], int a, int b) {
		long t = x[a];
		x[a] = x[b];
		x[b] = t;
	}
	public static void swap(double x[], int a, int b) {
		double t = x[a];
		x[a] = x[b];
		x[b] = t;
	}
	public static void swap(String x[], int a, int b) {
		String t = x[a];
		x[a] = x[b];
		x[b] = t;
	}
	
	
	/*************************************************************************
	 * @content: 快速排序（冒泡排序，选择排序(比冒泡减少了交换的次数)，插入排序）
	 *           高级排序（希尔排序）
	 * @param  : x[] 待交换元素的数组
	 * @param  : a 数组索引a
	 * @param  : b 数组索引b
	 * @author : 那建林
	 * @crtDate: 2010-02-16
	 * @modDate: 2010-02-17
	 */
	public static void sortByBubble(int[] x) {
		int j;
		for (int i =  x.length - 1; i > 1; i--) {
			for (j = 0; j < i; j++) {
				if (x[j] > x[j + 1]) {
					swap(x, j, j + 1);
				}
			}
		}
	}
	public static void sortBySelect(int[] x) {
		int minIndex, j;
		for (int i = 0; i < x.length - 1; i++) {
			minIndex = i;
			for (j = i + 1; j < x.length; j++) {
				if (x[minIndex] > x[j]) {
					minIndex = j;
				}
			}
			swap(x, minIndex, i);
		}
	}
	public static void sortByInsert(int[] x) {
		int tempInt, j;
		for (int i = 1;i < x.length; i++) {
			tempInt = x[i];
			j = i;
			while (j > 0 && x[j - 1] >= tempInt) {
				x[j] = x[j - 1];
				j--;
			}
			x[j] = tempInt;
		}
	}
	public static void sortByShell(int[] x) {
		int h = 1, i, j, tempInt;
		while (h <= x.length / 3) {
			h = h*3 + 1;
		}
		while (h > 0) {
			for (i = h; i < x.length; i++) {
				tempInt = x[i];
				j = i;
				while (j > h - 1 && x[j - h] >= tempInt) {
					x[j] = x[j - h];
					j -= h;
				}
				x[j] = tempInt;
			}
			h = (h - 1) / 3;
		}
	}
	
	
	/*************************************************************************
	 * @content: 转换为Long
	 * @param  : str 待转换的String
	 * @return : Long
	 * @remark : 
	 * @author : 那建林
	 * @crtDate: 2010-12-13 19:52:32
	 * @modDate: 2010-12-13 19:52:32
	 */	
	public static Long parseLong(String str){
		if (isDecimalType(str)) {
			str = str.substring(0, str.indexOf("."));
			return Long.parseLong(str);
		} else if (isIntegerType(str)) {
			return Long.parseLong(str);
		} 
		return null;
	}
	
	/*************************************************************************
	 * @content: 转换为BigDecimal
	 * @param  : str 待转换的String
	 * @return : BigDecimal
	 * @author : 那建林
	 * @crtDate: 2012-04-17 18:09
	 * @modDate: 2010-04-17 18:09
	 */	
	public static BigDecimal parseBigDecimal(String s){
		if (!isDecimalType(s) && !isIntegerType(s)) return null;
		return new BigDecimal(s);
	}
	
	
	/*************************************************************************
	 * @content: 把以","号隔开的String字符串转换为String数组
	 * @param  : str 待转换的String
	 * @return : String[] 
	 * @remark : 
	 * @author : 那建林
	 * @crtDate: 2010-05-11
	 * @modDate: 2010-05-11
	 */	
	public static Long[] getLongArrayFromComma(String str){
		if (StringUtils.isBlank(str)) return null;
		String[] strArray = str.trim().split(PropertyConst.COMMA);
		Long[] longArray = new Long[strArray.length];
		for (int i = 0; i < longArray.length; i++) {
			longArray[i] = Long.parseLong(strArray[i]);
		}
		return longArray;
	}
	

	/*************************************************************************
	 * @content: 打印出数组元素
	 * @param  : x[] 待打印的数组
	 * @author : 那建林
	 * @crtDate: 2010-02-17
	 * @modDate: 2010-02-17
	 */
	public static void displayArrays(int[] x) {
		StringBuilder sb = new StringBuilder();
		sb.append("数组长度为：").append(x.length)
			.append("，元素如下：").append(PropertyConst.LINE_SEPARATOR);
		for (int i = 0; i < x.length; i++) {
			sb.append(x[i]).append(PropertyConst.SPACE);
			if (((i + 1) % 20 == 0) && (i + 1 < x.length)) {
				sb.append(PropertyConst.LINE_SEPARATOR);
			}
		}
		log.info(sb);
	}
	
	
	/*************************************************************************
	 * @content: 高效判断是否为奇数
	 * @param  : i待传参数
	 * @author : 那建林
	 * @crtDate: 2011-09-28
	 * @modDate: 2011-09-28
	 */
	public static boolean isOdd(int i) {
		return (i & 1) != 0;
	}
	public static void main(String[] args) throws Exception {
		printBackNubmer(5);
	}
	/*************************************************************************
	 * @content: 打印回宫格
	 * @param  : arg待传参数
	 * @author : 那建林
	 * @crtDate: 2011-09-28
	 * @modDate: 2011-09-28
	 */
	public static void printBackNubmer(int arg) throws Exception {
		for (int i = 0; i < arg * 2 - 1; i++) {
			int hi = Math.abs(arg - 1 - i);
			for (int j = 0; j < arg * 2 - 1; j++) {
				int hj = Math.abs(arg - 1 - j);
				System.out.print(" " + (Math.max(hi, hj) + 1));
			}
			System.out.println();
		}
	}
}